// This file is part of Module Proxy.

// Module Proxy is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Module Proxy is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Module Proxy.  If not, see <https://www.gnu.org/licenses/>.


//         Copyright (C) 2021 - 2030  关中麦客  
//         All rights reserved
//
//         mod_urlmap.rs
//         唯一URL映射
//
//         created by 关中麦客 1036038462@qq.com

use bytes::{BufMut, BytesMut};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{TcpListener};
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use tokio::net::TcpStream;
use hyper::{Body, Request, Response, Error};
use serde_json::{Value};

const RSP_OK: &str = "{\"status\":\"ok\"}";
const RSP_ERROR: &str = "{\"status\":\"error\"}";

/// 初始化
pub async fn init()
{
    //唯一URL非使能（被注释）
    if !super::conf::enable_module_url()
    {
        return;  
    }

    log::info!("mod_url init...");

    //配置文件中有唯一URL的配置（未注释）
    if let Some(port) = super::conf::module_url_port()
    {
        // TCP 侦听------------
        let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), port);
        let listener = TcpListener::bind(addr).await.unwrap();

        log::info!("mod_url listening port: {}", port);

        tokio::spawn(async move {
            loop 
            {
                // accept
                let (socket, _) = listener.accept().await.unwrap();
                process(socket).await;
            }
        });
    }
}

/// 模块名是否对应
pub fn exist(module_name: &str) -> bool
{
    if let Some(name) = super::conf::module_url_name()
    {
        if name == module_name  //模块名称一致
        {
            return true;
        }
    }

    false
}

/// 唯一URL转发
pub async fn forward(request: Request<Body>, mod_name: &str) -> Result<Response<Body>, Error>
{
    // http://mysite.com:80/aaa/NMRMI41a 中保留 /aaa/NMRMI41a
    let url_path = request.uri().path_and_query().map(|x| x.as_str()).unwrap_or("/");
    //url_path去除module部分，只剩下映射key部分
    let remove_str = format!("/{}/", mod_name); 
    let key = &url_path[remove_str.len()..];

    if let Some((mtype, val, _timeout)) = super::mod_urlmap::get(key).await
    {
        if super::mod_urlmap::MapType::Url == mtype  //http反向代理
        {
            if let Ok(uri) = val.parse::<hyper::Uri>()
            {
                return super::mod_http::client_uri(uri).await;
            }
        }
        else   //本地文件
        {
            return Ok(super::mod_html::read_file(val).await);
        }
    }

    Ok(super::response::rsp_500().await)
}

/// 处理socket
async fn process(mut socket: TcpStream)
{
    //如果第一个字符是 '{' 或者 '['，表示是单条请求信息，否则是多条请求信息。
    //单条请求信息，消息最大长度小于4096。
    //多条请求信息需要冠以12字节长度单元，消息长度不受限制。

    //读取第一个字节消息，来判断请求信息类型
    let mut isonce: bool = true;         //信息类型: 单条
    let mut first: [u8; 1] = [0; 1];
    match socket.peek(&mut first).await  //peek不消费TcpStream中本次读取的数据,即peek后还可以再次读取这部分数据
    {
        Ok(_) =>
        {
            let c = first[0] as char;
            if c != '{' && c != ']'
            {
                isonce = false; //信息类型: 多条
            }
        }
        Err(err) =>
        {
            log::warn!("[mod_url] socket read first byte error: {}", err);
            return;
        }
    }

    //-------------------单条请求-------------------------
    if isonce
    {
        let mut buf: [u8; 4096] = [0; 4096];                //缓冲
        if let Ok(c_size) = socket.read(&mut buf).await     //socket读
        {
            //[u8]转&str
            let req_str: &str;
            match std::str::from_utf8(&buf[..c_size]) 
            {
                Ok(s) =>
                    req_str = s,
                Err(err) =>
                {
                    log::warn!("[mod_url] socket read msg from [u8] to &str error: {}", err);
                    return;
                }
            }

            //解析请求报文
            let rsp_str = parse_once(req_str).await;     

            //socket返回
            let send_bytes = rsp_str.as_bytes();
            if let Err(err) = socket.write_all(&send_bytes).await
            {
                log::warn!("[mod_url] socket write error: {}", err);
            }
        }

        return;
    }

    //-------------------多条请求-------------------------
    //读取12字节长度单元
    let mut len_buf: [u8; 12] = [0; 12]; 
    match socket.read(&mut len_buf).await
    {
        Ok(c_size) =>
        {
            if c_size != 12   
            {
                log::warn!("[mod_url] socket read len_buf error: len_buf size not 12");
                return;
            }
        },
        Err(err) =>
        {
            log::warn!("[mod_url] socket read length error: {}", err);
            return;
        }
    }

    //解析消息长度
    let _msg_len: usize;
    match String::from_utf8(len_buf.to_vec())
    {
        Ok(s) =>
        {
            let len_str = s.trim();
            match len_str.parse::<usize>()
            {
                Ok(len) =>
                    _msg_len = len,
                Err(err) =>
                {
                    log::warn!("[mod_url] socket read length error: {}", err);
                    return;
                }
            }
        },
        Err(err) =>
        {
            log::warn!("[mod_url] socket read length error: {}", err);
            return;
        }
    }

    //读取缓冲区
    let mut buffer = BytesMut::new();           //读取rsp_json缓冲区
    let mut read_buf: [u8; 4096] = [0; 4096];   //socket读缓冲

    loop 
    {
        //已读取了完整数据
        if buffer.len() >= _msg_len
        {
            let read_bytes = buffer.to_vec();                       //BytesMut转Vec<u8>
            if let Ok(req_str) = String::from_utf8(read_bytes)      //Vec<u8>转String
            {
                let rsp_str = parse_mut(&req_str).await;      //解析请求报文

                //socket返回
                let send_bytes = rsp_str.as_bytes();
                if let Err(err) = socket.write_all(send_bytes).await
                {
                    log::warn!("[mod_url] socket write error: {}", err);
                }
            }

            break;  //跳出loop
        }

        //从socket中分次读取，合并到buffer
        if let Ok(c_size) = socket.read(&mut read_buf).await
        {
            buffer.put(&read_buf[..c_size]); 
        }
    }
}

/// 解析单条数据, 返回json应答
async fn parse_once(req_str: &str) -> String
{
    let json = parse_json(req_str);
    match json["method"].as_str()
    {
        Some("set") =>
        {
            // json示例： {"method":"set","key":"NMRMI41a","type":"url","val":"http://xxxx/xxx/xx","timeout":-1}
            let mut mtype = super::mod_urlmap::MapType::File;
            if let Some(key) = json["key"].as_str()
            {
                if let Some(mytpe_str) = json["type"].as_str()
                {
                    if "url" == mytpe_str
                    {
                        mtype = super::mod_urlmap::MapType::Url;
                    }

                    if let Some(val) = json["val"].as_str()
                    {
                        if let Some(timeout) = json["timeout"].as_i64()
                        {
                            super::mod_urlmap::set(key.to_string(), mtype, val.to_string(), timeout as i32).await;
                            return RSP_OK.to_string();
                        }
                    }
                }
            }

            log::warn!("[mod_url] error: Json parsing set method format error.");
            return RSP_ERROR.to_string();        
        }
        Some("del") =>
        {
            // json示例： {"method":"del","key":"NMRMI41a"}
            if let Some(key) = json["key"].as_str()
            {
                super::mod_urlmap::del(key.to_string()).await;  //从map中删除
                return RSP_OK.to_string();    
            }

            log::warn!("[mod_url] error: json parse del method without key.");
            return RSP_ERROR.to_string();
        }
        Some("get") =>
        {
            // json示例： {"method":"get","key":"NMRMI41a"}
            if let Some(key) = json["key"].as_str()
            {
                if let Some((mtype, val, timeout)) = super::mod_urlmap::get(key).await
                {
                    let rsp: String;
                    if mtype == super::mod_urlmap::MapType::File
                    {
                        rsp = format!("\"key\":\"{}\",\"type\":\"file\",\"val\":\"{}\",\"timeout\":{}", 
                                        key, val, timeout);
                    }
                    else
                    {
                        rsp = format!("\"key\":\"{}\",\"type\":\"url\",\"val\":\"{}\",\"timeout\":{}", 
                                        key, val, timeout);
                    }

                    let rsp = "{".to_string() + &rsp + "}";
                    return rsp;    
                }
            }

            log::warn!("[mod_url] error: json parse get method without key.");
            return RSP_ERROR.to_string();
        }
        Some(_) =>
        {
            log::warn!("[mod_url] error: json parse unknown method");
            return RSP_ERROR.to_string();
        },
        None =>
        {
            log::warn!("[mod_url] error: json parse unknown request");
            return RSP_ERROR.to_string();
        }
    }
}

/// 解析多条数据, 返回json应答
async fn parse_mut(req_str: &str) -> String
{
    let mut ok_num: i32 = 0;

    let lines = req_str.split("\r\n");
    for line in lines
    {
        let json = parse_json(line);  //一行json： {"key":"NMRMI41a","type":"url","val":"http://xxxx/xxx/xx","timeout":-1}

        let mut mtype = super::mod_urlmap::MapType::File;
        if let Some(key) = json["key"].as_str()
        {
            if let Some(mytpe_str) = json["type"].as_str()
            {
                if "url" == mytpe_str
                {
                    mtype = super::mod_urlmap::MapType::Url;
                }

                if let Some(val) = json["val"].as_str()
                {
                    if let Some(timeout) = json["timeout"].as_i64()
                    {
                        super::mod_urlmap::set(key.to_string(), mtype, val.to_string(), timeout as i32).await;
                        ok_num += 1;
                    }
                }
            }
        }
    }

    //返回json
    let rsp = format!("\"status\":\"ok\",\"ok_amount\":{}", ok_num);
    let rsp = "{".to_string() + &rsp + "}";
    rsp
}

/// 解析json
fn parse_json(msg: &str) -> Value
{
    match serde_json::from_str(msg)
    {
        Ok(json) => json,
        Err(err) =>
        {
            log::warn!("parse json error: {}", err);
            let json = serde_json::json!({"method":"error"});
            json
        }
    }
}